﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using t_DeepTalkRenderServiceLib.DTDBService;
using IndicoInterface;
using System.Threading;
using DeepTalkRenderServiceLib;
using System.Diagnostics;

namespace t_DeepTalkRenderServiceLib
{
    /// <summary>
    /// Tests of the RenderService (i.e. does it work!?!?).
    /// </summary>
    [TestClass]
    public class t_RenderMeetingTask
    {
        public t_RenderMeetingTask()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestInitialize]
        public void InitTest()
        {
            Utils.StartMainService();
            FileInfo db = new FileInfo("ConfData_" + TestContext.TestName + ".sdf");
            File.Copy(@"..\..\..\DeepTalkDBService\ConferenceData.sdf", db.FullName);
            using (DTDBClient rc = new DTDBClient())
            {
                rc.SetDBFile(db);
            }
        }

        [TestCleanup]
        public void TestCleanup()
        {
            Utils.ShutdownMainService();
        }

        /// <summary>
        /// Submit a single talk and make sure it gets rendered.
        /// </summary>
        [TestMethod]
        [Timeout(10*1000)]
        public void TestOneTalk()
        {
            string url = "http://indico.cern.ch/conferenceDisplay.py?confId=a042880";
            Utils.SubmitTalk(url);

            AutoResetEvent ar = new AutoResetEvent(false);
            string seenUrl = null;
            var t = RenderMeetingTask.Start((strXML, id) =>
            {
                seenUrl = AgendaInfo.Deseralize(strXML).ConferenceID;
                ar.Set();
                var result = new RenderMeetingTask.RenderResultsInfo()
                {
                    HowLongToNextUpdate = null,
                    NumberOfTalks = 10,
                    SizeOfRender = (float)5.0,
                    MeetingEnd = DateTime.Now,
                    MeetingStart = DateTime.Now,
                    Title="Grand Old Talk"
                };
                Trace.WriteLine(DateTime.Now + " Done with the rendering");
                return result;
            }, "Net.TCP");
            ar.WaitOne();
            Assert.AreEqual("a042880", seenUrl, "The wrong conference came back... HUH!?");
            t.Wait();
            using (var rc = new DTDBClient())
            {
                Trace.WriteLine(DateTime.Now + " Now going to look to see if there are any rendered talks!");
                Assert.AreEqual(1, rc.GetRecentlyRenderedTalks(1).Length, "Expected a rendered talk!");
            }
        }

        /// <summary>
        /// Submit a single talk and make sure it gets rendered.
        /// </summary>
        [TestMethod]
        [Timeout(10 * 1000)]
        public void TestReturnedMetaData()
        {
            string url = "http://indico.cern.ch/conferenceDisplay.py?confId=a042880";
            Utils.SubmitTalk(url);

            AutoResetEvent ar = new AutoResetEvent(false);
            DateTime startAndEnd = DateTime.Now;
            int talkID = -1;
            var t = RenderMeetingTask.Start((strXML, id) =>
            {
                talkID = id;
                ar.Set();
                var result = new RenderMeetingTask.RenderResultsInfo()
                {
                    HowLongToNextUpdate = null,
                    NumberOfTalks = 10,
                    SizeOfRender = (float)5.0,
                    MeetingEnd = startAndEnd,
                    MeetingStart = startAndEnd,
                    Title = "Grand Old Talk"
                };
                Trace.WriteLine(DateTime.Now + " Done with the rendering");
                return result;
            }, "Net.TCP");
            ar.WaitOne();
            t.Wait();
            using (var rc = new DTDBClient())
            {
                Assert.IsTrue((startAndEnd - rc.GetConferenceEndDate(talkID)).TotalSeconds < 1.0, "Expected the talk end times to be the same");
            }
        }

        /// <summary>
        /// Render a talk, but crash on the way out... and then make sure that the
        /// talk is still on the update list.
        /// </summary>
        [TestMethod]
        [Timeout(10 * 1000)]
        public void TestCrashedTalk()
        {
            string url = "http://indico.cern.ch/conferenceDisplay.py?confId=a042880";
            Utils.SubmitTalk(url);

            AutoResetEvent ar = new AutoResetEvent(false);
            int talkID = 0;
            var t = RenderMeetingTask.Start((strXML, id) =>
            {
                talkID = id;
                ar.Set();
                throw new ArgumentException("ops!");
            }, "Net.TCP");
            ar.WaitOne();
            t.Wait();
            using (var rc = new DTDBClient())
            {
                Assert.AreEqual(0, rc.GetRecentlyRenderedTalks(1).Length, "Expected no rendered talk!");
                var dt = rc.GetNextUpdateTime(talkID);
                Assert.IsTrue(dt.HasValue, "The next render time has no value!");
                double delta = (dt.Value - DateTime.Now).TotalMinutes;
                Assert.IsTrue(delta > 55 && delta < 61, "Expected at least 55 minutes before the next run and less than 61 (" + delta + ")");
            }
        }
    }
}
